use super::error::ApiError::{self, *};
use crate::{ApiResult, Auth};
use axum::response::{IntoResponse, Response};
use log::error;
use serde::Serialize;

/// 成功返回码
const SUCCESS: u8 = 0;
/// 失败返回码
const FAIL: u8 = 1;
/// 未登录返回码
const NO_TOKEN: u8 = 2;
/// token过期返回码
const TOKEN_EXPIRE: u8 = 3;

/// 统一的返回类型
#[derive(Serialize, Debug, Clone)]
pub struct R<T = ()> {
    code: u8,
    message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    data: Option<T>,
}

impl<T: Serialize> R<T> {
    /// 返回业务失败信息
    pub fn fail<M: AsRef<str>>(message: M) -> Self {
        let message = String::from(message.as_ref());
        R {
            code: FAIL,
            data: None,
            message,
        }
    }

    /// 认证失败
    pub fn auth_fail(auth: Auth) -> Self {
        let message = auth.to_string();
        match auth {
            Auth::NoToken => R {
                code: NO_TOKEN,
                data: None,
                message,
            },
            Auth::TokenExpire => R {
                code: TOKEN_EXPIRE,
                data: None,
                message,
            },
        }
    }

    /// 返回无 data 的成功信息
    pub fn ok() -> Self {
        R {
            code: SUCCESS,
            data: None,
            message: "操作成功".to_string(),
        }
    }

    /// 返回有 data 的成功信息
    pub fn success(data: T) -> Self {
        R {
            code: SUCCESS,
            data: Some(data),
            message: "操作成功".to_string(),
        }
    }
}

/// 为 [R<T>] 实现 [IntoResponse] trait
impl<T: Serialize> IntoResponse for R<T> {
    fn into_response(self) -> Response {
        axum::Json(self).into_response()
    }
}

/// 将自定义的[ApiError]转成 [R]
impl<T: Serialize> From<ApiError> for R<T> {
    fn from(e: ApiError) -> Self {
        match e {
            Biz(_) | Validation(_) => R::fail(e.to_string()),
            Path(_) => {
                error!("{}", e);
                R::fail("路径参数错误")
            }
            Query(_) => {
                error!("{}", e);
                R::fail("查询参数错误")
            }
            Json(_) => {
                error!("{}", e);
                R::fail("请求参数错误")
            }
            Form(_) => {
                error!("{}", e);
                R::fail("表单参数错误")
            }
            Authorization(auth) => R::auth_fail(auth),
            Redis(_) => {
                error!("{}", e);
                R::fail("reids错误")
            },
        }
    }
}

/// 将自定义的[Result]转成 [R]
impl<T: Serialize> From<ApiResult<T>> for R<T> {
    fn from(res: ApiResult<T>) -> Self {
        match res {
            Ok(data) => R::success(data),
            Err(e) => e.into(),
        }
    }
}
